<template>
	<view class="h-list" ref="h-list"
		@touchstart="handlerDropStart" 
		@touchmove="handlerDropMove" 
		@touchend="handlerDropUp"
		@touchcancel="handlerDropUp"
		@mousedown="handlerDropStart" 
		@mousemove="handlerDropMove" 
		@mouseup="handlerDropUp">
		<view class="h-load-wrapper" :class="[isShow&&'show', refreshing&&'reset']"
			:style="{ 
				top: moveY + 'rpx',
				opacity: opacity
			}">
			<view class="h-load"
				:class="refreshing&&'loading'"
				:style="{
					transform: `rotate(${moveY}deg)`
				}"></view>
		</view>
		<view class="h-list-scroll">
			<slot></slot>
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				refreshing: false,
				draging: false,
				startY: 0,
				moveY: 0,
				opacity: 0,
				isShow: false,
				timer: ''
			}
		},
		methods: {
			handlerDropStart(e) {
				if(!this.timer) {
					if(!this.refreshing) { //仅在非刷新中的状态才能拖拽
						this.draging = true //拖拽开始
						//记录初始Y值
						if(e.touches.length > 0) { //触摸
							this.startY = e.touches[0].clientY
						} else { //鼠标
							this.startY = e.clientY
						}
					}
				}
			},
			handlerDropMove(e) {
				if(this.draging) { //是否处于拖拽状态
					//计算y轴方向移动的距离
					let moveY = 0
					if(e.touches.length > 0) {
						moveY = (e.touches[0].clientY - this.startY)
					} else {
						moveY = e.clientY - this.startY
					}
					this.moveY = moveY > 400 ? 400 : moveY
					this.opacity = this.moveY / 200
					//只有移动距离大于等于20px才展示刷新标识除非标识已经展示了
					if(this.moveY >= 20||this.isShow) {
						this.isShow = true
					}
				}
			},
			async handlerDropUp(e) {
				if(this.draging) {
					this.draging = false //拖拽结束
					// 判断松手时的状态，移动距离大于60px才刷新
					if(this.moveY >= 60) {
						this.refreshing = true //将列表状态置为刷新中
						this.opacity = 1
						this.moveY = 40 //将load标识移动回标准位置
						await this.sleep(1000)
						this.$emit('refresh')
					} else {
						this.cancel()
					}					
				}
			},
			//刷新完成
			async completed() {
				this.moveY = -100
				this.startY = 0
				await this.sleep(500)
				this.draging = false
				this.refreshing = false
				this.isShow = false	
				this.opacity = 0
				this.timer = ''
			},
			//取消刷新
			cancel() {
				this.moveY = -100
				this.startY = 0
			},
			sleep(delay) {
				return new Promise(resolve => this.timer = setTimeout(resolve, delay))
			}
		}
	}
</script>

<style scoped>
	.h-list {
		position: relative;
		box-sizing: border-box;
		height: 100%;
		overflow: hidden;
	}
	
	.h-load-wrapper {
		position: absolute;
		left: 50%;
		transform: translate(-50%, -200%);
		transition-property: transform;
		transition-duration: .5s;
		z-index: 9;
	}
	
	.h-load-wrapper.show {
		transform: translate(-50%, 0%);
	}
	
	.h-load-wrapper.reset {
		transition-property: transform, top, opacity;
	}
	
	.h-load {
		width: 64rpx;
		height: 64rpx;
		background-color: #fff;
		border-radius: 50%;
		border: 2rpx solid #ececec;
		box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.1);
		display: flex;
		align-items: center;
		justify-content: center;
	}
	
	.h-load::before {
		content: '';
		display: block;
		width: 32rpx;
		height: 32rpx;
		border-radius: 50%;
		border: 6rpx solid #0081ff;
		border-right-color: transparent;
	}
	
	.h-load.loading {
		animation: loading 1s infinite linear;
	}
	
	@keyframes loading {
		0% {
			transform: rotate(0deg);
		}
		100% {
			transform: rotate(360deg);
		}
	}
	
	.h-list-scroll {
		width: 100%;
		height: inherit;
		overflow: scroll;
	}
</style>